<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>拓扑拖拽编辑器</title>
<style>
    #canvas {
        width: 800px;
        height: 600px;
        border: 1px solid #ccc;
        overflow: hidden;
        position: relative;
    }
    .node {
        cursor: move;
    }
    .link {
        fill: none;
        stroke: #000;
        stroke-width: 2;
    }
    .grid {
        stroke: #ddd;
        stroke-width: 1;
    }
</style>
</head>
<body>
<div id="canvas"></div>

<script>
    // 创建节点和链接的数据结构
    let nodes = [];
    let links = [];

    // 创建SVG画布
    const canvas = document.getElementById('canvas');
    const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
    svg.setAttribute('width', '800');
    svg.setAttribute('height', '600'); 
    canvas.appendChild(svg);

    // 创建背景网格
    const gridGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
    svg.appendChild(gridGroup);

    function drawGrid(x0,y0) {
        gridGroup.innerHTML = ''; // 清空之前的网格
        const gridSize = 20;
        const gridWidth = 800;
        const gridHeight = 600;

        for (let x = x0; x <= gridWidth+x0; x += gridSize) {
            const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
            line.setAttribute('class', 'grid');
            line.setAttribute('x1', x);
            line.setAttribute('y1', y0);
            line.setAttribute('x2', x);
            line.setAttribute('y2', gridHeight+y0);
            gridGroup.appendChild(line);
        }

        for (let y = y0; y <= gridHeight+y0; y += gridSize) {
            const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
            line.setAttribute('class', 'grid');
            line.setAttribute('x1', x0);
            line.setAttribute('y1', y);
            line.setAttribute('x2', gridWidth+x0);
            line.setAttribute('y2', y);
            gridGroup.appendChild(line);
        }
    }

    drawGrid(0,0); // 初始化绘制网格

    // 创建节点
    function createNode(x, y) {
        const node = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
        node.setAttribute('class', 'node');
        node.setAttribute('cx', x);
        node.setAttribute('cy', y);
        node.setAttribute('r', 20);
        node.setAttribute('fill', 'blue');
        node.setAttribute('stroke', 'black');
        node.setAttribute('stroke-width', 2);
        svg.appendChild(node);
        nodes.push({ x, y, element: node });
        // 添加拖拽事件
        node.addEventListener('mousedown', dragStart);
    }

    // 创建连接
    function createLink(sourceNode, targetNode) {
        const link = document.createElementNS('http://www.w3.org/2000/svg', 'line');
        link.setAttribute('class', 'link');
        link.setAttribute('x1', sourceNode.x);
        link.setAttribute('y1', sourceNode.y);
        link.setAttribute('x2', targetNode.x);
        link.setAttribute('y2', targetNode.y);
        svg.appendChild(link);
        links.push({ source: sourceNode, target: targetNode, element: link });
    }

    // 拖拽节点
    let selectedNode = null;
    let offsetX, offsetY;
    let prevX = 0;
    let prevY = 0;

    function dragStart(event) {
        event.preventDefault(); // 阻止默认行为
        selectedNode = nodes.find(node => node.element === event.target);
        offsetX = event.clientX - selectedNode.x;
        offsetY = event.clientY - selectedNode.y;
        prevX = event.clientX;
        prevY = event.clientY;
        document.addEventListener('mousemove', drag);
        document.addEventListener('mouseup', dragEnd);
    }

    function drag(event) {
        const deltaX = event.clientX - prevX;
        const deltaY = event.clientY - prevY;
        prevX = event.clientX;
        prevY = event.clientY;

        selectedNode.x += deltaX;
        selectedNode.y += deltaY;

        selectedNode.element.setAttribute('cx', selectedNode.x);
        selectedNode.element.setAttribute('cy', selectedNode.y);

        // 更新连接的位置
        updateLinks(selectedNode);
        // 阻止画布跟踪移动
        event.stopPropagation();
    }

    function dragEnd() {
        selectedNode = null;
        document.removeEventListener('mousemove', drag);
        document.removeEventListener('mouseup', dragEnd);
    }

    function updateLinks(node) {
        links.forEach(link => {
            if (link.source === node) {
                link.element.setAttribute('x1', node.x);
                link.element.setAttribute('y1', node.y);
            } else if (link.target === node) {
                link.element.setAttribute('x2', node.x);
                link.element.setAttribute('y2', node.y);
            }
        });
    }

    // 拖拽无限扩展画布
    let dragStartX = 0;
    let dragStartY = 0;
    let viewBoxX = 0;
    let viewBoxY = 0;
    let isDraggingCanvas = false;

    canvas.addEventListener('mousedown', function(event) {
        if (event.button === 0) {
            dragStartX = event.clientX;
            dragStartY = event.clientY;
            let viewBox = svg.getAttribute('viewBox');
            let gridWidth = 800;
            let gridHeight = 600;
            if (!viewBox) {
                viewBox = `0 0 ${gridWidth} ${gridHeight}`;
            }
            viewBox = viewBox.split(' ');
            viewBoxX = parseFloat(viewBox[0]);
            viewBoxY = parseFloat(viewBox[1]);
            isDraggingCanvas = true;
            document.addEventListener('mousemove', dragCanvas);
            document.addEventListener('mouseup', stopDragCanvas);
        }
    });

    function dragCanvas(event) {
        if (isDraggingCanvas) {
            let gridWidth = 800;
            let gridHeight = 600;
            const deltaX = event.clientX - dragStartX;
            const deltaY = event.clientY - dragStartY;
            svg.setAttribute('viewBox', `${viewBoxX - deltaX} ${viewBoxY - deltaY} ${gridWidth} ${gridHeight}`);
            drawGrid(viewBoxX - deltaX, viewBoxY - deltaY); // 重新绘制网格
        }
    }

    function stopDragCanvas() {
        isDraggingCanvas = false;
        document.removeEventListener('mousemove', dragCanvas);
        document.removeEventListener('mouseup', stopDragCanvas);
    }

    // 创建节点和连接示例
    createNode(100, 100);
    createNode(200, 200);
    createNode(300, 300);
    createLink(nodes[0], nodes[1]);
    createLink(nodes[1], nodes[2]);
</script>
</body>
</html>
